/**
 * ZHU framework. Copyright 2012-, all rights reserved.
 *
 * $Id: AbstractLifecycle.java 47 2012-09-20 06:31:35Z zhuxiaopeng $
 * $Revision: 47 $
 * $Date: 2012-09-20 14:31:35 +0800 (四, 2012-09-20) $
 * $Author: zhuxiaopeng $
 */
package zhu.framework.entity.lifecycle;

import java.util.*;
import java.util.logging.*;

import javax.persistence.*;

import zhu.framework.entity.*;
import zhu.framework.entity.Entity;
import zhu.framework.util.*;

/**
 * <p>
 * </p>
 * 
 * @author $Author: zhuxiaopeng $
 * @version $Revision: 47 $ - $Date: 2012-09-20 14:31:35 +0800 (四, 2012-09-20) $
 */
public abstract class AbstractLifecycle<T extends Entity> implements Lifecycle<T> {
	/**
	 * このClassのデフォルトの<code>Logger</code>取得する。
	 * 特に理由のない限り、このClass内ではこのメソッドを通じてLoggerを取得することを推奨する。
	 * 
	 * @return このClassのデフォルトの<code>Logger</code>
	 */
	static private Logger getLogger() {
		final LoggerManager manager = LoggerManager.getInstance();
		final Logger logger = manager.getLogger(AbstractLifecycle.class);
		return logger;
	}

	public AbstractLifecycle(final LifecycleContext lifecycleContext) {
		MyUtility.checkMethodParameterNotNull("lifecycleContext", lifecycleContext);
		this.lifecycleContext = lifecycleContext;
	}

	@Override
	public T create(final T newEntity) {
		final EntityManager em = getEntityManager();
		em.persist(newEntity);
		return newEntity;
	}

	@Override
	public T create(final EntityUpdator<T> updator) {
		final T newEntity = newInstance();
		if (updator != null) {
			updator.updateProperties(newEntity);
		}
		final EntityManager em = getEntityManager();
		em.persist(newEntity);
		return newEntity;
	}

	@Override
	public T update(final T entity, final EntityUpdator<T> updator) {
		MyUtility.checkMethodParameterNotNull("entity", entity);
		if (updator != null) {
			updator.updateProperties(entity);
		}
		final EntityManager em = getEntityManager();
		final T db = findById(entity.getEntityId());
		if (entity.getEntityVersion().equals(db.getEntityVersion()) == false) {
			throw new OptimisticLockException("他のユーザによってデータが変更されたため保存できません。");
		}
		return em.merge(entity);
	}

	@Override
	public void remove(final T entity) {
		MyUtility.checkMethodParameterNotNull("entity", entity);
		final EntityManager em = getEntityManager();
		em.remove(findById(entity.getEntityId()));
	}

	@Override
	public void removeAll(final Collection<T> entityList) {
		MyUtility.checkMethodParameterNotNull("entity", entityList);
		final EntityManager em = getEntityManager();
		for (final T t : entityList) {
			em.remove(findById(t.getEntityId()));
		}
	}

	@Override
	public T findById(final EntityId id) {
		MyUtility.checkMethodParameterNotNull("id", id);
		final EntityManager em = getEntityManager();
		return em.find(getEntityType(), id.getId());
	}

	@SuppressWarnings("unchecked")
	protected final <X> X getSingleQueryResult(final Query query) {
		final Logger logger = getLogger();
		//
		try {
			return (X) query.getSingleResult();
		} catch (final NoResultException e) {
			if (logger.isLoggable(Level.FINER)) {
				logger.finer("Entity is not found by the query : returns null");
			}
			return null;
		} catch (final EntityNotFoundException e) {
			if (logger.isLoggable(Level.FINER)) {
				logger.finer("Entity is not found by the query : returns null");
			}
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	protected final <X> List<X> getQueryResultList(final Query query) {
		return query.getResultList();
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @return
	 */
	protected final EntityManager getEntityManager() {
		return getLifecycleContext().getEntityManager();
	}

	/**
	 * <p>
	 * </p>
	 * 
	 * @return
	 */
	protected final LifecycleFactory getLifecycleFactory() {
		return getLifecycleContext().getLifecycleFactory();
	}

	/**
	 * <p>
	 * プロパティ<code>lifecycleContext</code>の値を取得する。
	 * </p>
	 * 
	 * @return プロパティ<code>lifecycleContext</code>の値
	 */
	protected synchronized LifecycleContext getLifecycleContext() {
		return lifecycleContext;
	}

	private final LifecycleContext lifecycleContext;

}
